const PENDING = "pending"; // 等待
const FULFILLED = "fulfilled"; // 成功
const REJECTED = "reject"; // 失败
const isFunction = (value) => typeof value === "function";
class MyPromise {
  // Promise 状态
  status = PENDING;
  // 成功的值
  value = undefined;
  // 失败的值
  reason = undefined;
  // 成功回调
  successCallback = [];
  // 失败回调
  failCallback = [];
  // 执行器中需要捕获错误
  constructor (callback) {
    try {
      callback(this.resolve, this.reject);
    } catch (e) {
      this.reject(e);
    }
  }
  resolve = (value) => {
    // 如果状态不是等待，阻止程序向下执行
    if (this.status !== PENDING) {
      return;
    }
    // 将状态更改为成功
    this.status = FULFILLED;
    // 保存成功的值
    this.value = value;
    // 判断成功回调是否存在，如果存在 调用
    // this.successCallback && this.successCallback(this.value)
    while (this.successCallback.length) {
      // 调用shift方法然后每次执行的时候，推出方法出数组栈，并且将数据返回回去
      this.successCallback.shift()();
    }
  };
  reject = (value) => {
    // 如果状态不是等待，阻止程序向下执行
    if (this.status !== PENDING) {
      return;
    }
    // 将状态更改为失败
    this.status = REJECTED;
    // 保存失败的值
    this.reason = value;
    // 判断失败回调是否存在，如果存在 调用
    // this.failCallback && this.failCallback(this.reason)
    while (this.failCallback.length) {
      // 调用shift方法然后每次执行的时候，推出方法出数组栈，并且将数据返回回去
      this.failCallback.shift()();
    }
  };
  then (successCallback, failCallback) {
    successCallback = isFunction(successCallback)
      ? successCallback
      : (value) => value;
    failCallback = isFunction(failCallback)
      ? failCallback
      : (err) => {
        throw err;
      };
    let thenPromise = new MyPromise((resolve, reject) => {
      // 如果是成功的状态
      if (this.status === FULFILLED) {
        setTimeout(() => {
          try {
            let x = successCallback(this.value);
            // 判断x是否 MyPromise 类
            // 是 就直接
            resolvePromise(thenPromise, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        }, 0);
        // resolve(x)
      } else if (this.status === REJECTED) {
        setTimeout(() => {
          try {
            let x = failCallback(this.reason);
            resolvePromise(thenPromise, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        }, 0);
      } else {
        // 等待的情况
        this.successCallback.push(() => {
          setTimeout(() => {
            try {
              let x = successCallback(this.value);
              resolvePromise(thenPromise, x, resolve, reject);
            } catch (e) {
              reject(e);
            }
          }, 0);
        });
        this.failCallback.push(() => {
          setTimeout(() => {
            try {
              let x = failCallback(this.reason);
              resolvePromise(thenPromise, x, resolve, reject);
            } catch (e) {
              reject(e);
            }
          }, 0);
        });
      }
    });
    return thenPromise;
  };
  finally (callback) {
    return this.then(value => {
      return MyPromise.resolve(callback()).then(() => value)
    }, reason => {
      return MyPromise.resolve(callback()).then(() => { throw reason })
    })
  };
  catch (failCallback) {
    return this.then(undefined, failCallback)
  };
  static all (array) {
    // 存储结果
    let result = [];
    let index = [];
    return new MyPromise((resolve, reject) => {
      function addData (key, value) {
        // 这里是为了按照执行顺序放入值，保证顺序不会乱！
        result[key] = value
        index++;
        if (index === array.length) {
          resolve(result)
        }
      }
      // 这里为什么用for循环而不用
      for (const i in array) {
        let current = array[i]
        if (current instanceof MyPromise) {
          // MyPromise对象
          current.then(value => addData(i, value), reason => reject(reason))
        } else {
          // 非MyPromise对象
          addData(i, current)
        }
      }
    })
  };
  static resolve (value) {
    if (value instanceof MyPromise) {
      // MyPromise对象
      return value
    } else {
      // 非MyPromise对象
      return new MyPromise(resolve => resolve(value))
    }
  }
}
// 解析是否promise函数
// 不是直接调用reslove
// 是的话根据情况调用 reslove 或者 reject
function resolvePromise (thenPromise, value, resolve, reject) {
  if (thenPromise === value) {
    return reject(
      new TypeError("Chaining cycle detected for promise #<MyPromise>")
    );
  }
  if (value instanceof MyPromise) {
    value.then(resolve, reject);
  } else {
    resolve(value);
  }
}
